//
//  Types.cpp
//  Simulation
//
//  Created by Christopher Kemsley on 2/24/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//

#include "Types.hpp"

#include <ostream>
#include <limits.h>
#include <cmath>


#define	MegaLong	1000000
#define	MegaDouble	1000000.



NamespaceBegin

std::ostream&	operator<<	( std::ostream & stream , Interval const & interval )
	{
	stream << "<" ;
	
	stream << interval.mSeconds << "s" ;
	
	if ( interval.mMicroseconds || interval.mPicoseconds )
		{
		unsigned long	m	=	interval.mMicroseconds / 1000 ;
		unsigned long	u	=	interval.mMicroseconds % 1000 ;
		
		stream << " " ;
		stream << m << " " ;
		stream << u << "" ;
		}
	
	if ( interval.mPicoseconds )
		{
		unsigned long	n	=	interval.mPicoseconds / 1000 ;
		unsigned long	p	=	interval.mPicoseconds % 1000 ;
		
		stream << " " ;
		stream << n << " " ;
		stream << p << "" ;
		}
	
	stream << ">" ;
	
	return stream ;
	}

std::ostream&	operator<<	( std::ostream & stream , Location const & location )
	{
	stream << "<x,y=" ;
	
	stream << location.x << "," << location.y ;
	
	stream << ">" ;
	
	return stream ;
	}

std::ostream&	operator<<	( std::ostream & stream , Channel const & channel )
	{
	stream << "<Channel " ;
	
	if ( channel.identifier == Channel::Unidentified )
		stream << "Unspecified" ;
	else
		stream << channel.identifier ;
	
	stream << ">" ;
	
	return stream ;
	}

NamespaceEnd







using namespace Sim ;


Interval const	Interval :: distantFuture	( LONG_MAX , 999999 , 999999 ) ;
Interval const	Interval :: zeroTime		( 0 , 0 , 0 ) ;








Interval :: Interval	()
:	mSeconds		( 0 )
,	mMicroseconds	( 0 )
,	mPicoseconds	( 0 )
	{
	
	}
Interval :: Interval	( Interval const & copy )
:	mSeconds		( copy.mSeconds )
,	mMicroseconds	( copy.mMicroseconds )
,	mPicoseconds	( copy.mPicoseconds )
	{
	
	}
Interval :: Interval	( double seconds )
:	mSeconds		( seconds )
,	mMicroseconds	( 0 )
,	mPicoseconds	( 0 )
	{
	seconds			-=	mSeconds ;
	seconds			*=	MegaDouble ;
	mMicroseconds	=	seconds ;
	seconds			-=	mMicroseconds ;
	seconds			*=	MegaDouble ;
	mPicoseconds	=	seconds ;
	}
Interval :: Interval	( unsigned long seconds , unsigned long microseconds , unsigned long picoseconds )
:	mSeconds		( seconds )
,	mMicroseconds	( microseconds )
,	mPicoseconds	( picoseconds )
	{
	_compressUpward() ;
	_compressDownward() ;
	}
Interval :: ~Interval	()
	{
	
	}


double Interval :: secondsValue () const
	{
	double	value	=	(double)mPicoseconds ;
	value			/=	MegaDouble ;
	value			+=	(double)mMicroseconds ;
	value			/=	MegaDouble ;
	value			+=	(double)mSeconds ;
	return value ;
	}
bool		Interval :: isNegative () const
	{
	if ( mSeconds < 0 )
		return true ;
	else if ( mSeconds == 0 )
		{
		if ( mMicroseconds < 0 )
			return true ;
		else if ( mMicroseconds == 0 )
			{
			if ( mPicoseconds < 0 )
				return true ;
			}
		}
	return false ;
	}
Interval&	Interval :: operator=	( Interval const & copy )
	{
	mSeconds		=	copy.mSeconds ;
	mMicroseconds	=	copy.mMicroseconds ;
	mPicoseconds	=	copy.mPicoseconds ;
	return *this ;
	}


Interval const	Interval :: operator+	( Interval const & copy ) const
	{
	return Interval ( mSeconds+copy.mSeconds , mMicroseconds+copy.mMicroseconds , mPicoseconds+copy.mPicoseconds ) ;
	}
Interval const	Interval :: operator-	( Interval const & copy ) const
	{
	Interval	me	( *this ) ;
	me -= copy ;
	return me ;
	}
Interval const	Interval :: operator*	( unsigned const & copy ) const
	{
	Interval	i	( *this ) ;
	i.mPicoseconds	*=	copy ;
	i.mMicroseconds	*=	copy ;
	i.mSeconds		*=	copy ;
	i._compressDownward() ;
	return i ;
	}

Interval&	Interval :: operator+=	( Interval const & copy )
	{
	mSeconds		+=	copy.mSeconds ;
	mMicroseconds	+=	copy.mMicroseconds ;
	mPicoseconds	+=	copy.mPicoseconds ;
	
	_compressDownward() ;
	
	return *this ;
	}
Interval&	Interval :: operator-=	( Interval const & copy )
	{
	mSeconds		-=	copy.mSeconds ;
	mMicroseconds	-=	copy.mMicroseconds ;
	mPicoseconds	-=	copy.mPicoseconds ;
	
	_compressUpward() ;
	
	return *this ;
	}


bool	Interval :: operator==	( Interval const & compare ) const
	{
	if ( mSeconds != compare.mSeconds )
		return false ;
	if ( mMicroseconds != compare.mMicroseconds )
		return false ;
	if ( mPicoseconds != compare.mPicoseconds )
		return false ;
	return true ;
	}
bool	Interval :: operator!=	( Interval const & compare ) const
	{
	if ( mSeconds != compare.mSeconds )
		return true ;
	if ( mMicroseconds != compare.mMicroseconds )
		return true ;
	if ( mPicoseconds != compare.mPicoseconds )
		return true ;
	return false ;
	}

bool	Interval :: operator>	( Interval const & compare ) const
	{
	return secondsValue() > compare.secondsValue() ;
	}
bool	Interval :: operator<	( Interval const & compare ) const
	{
	return secondsValue() < compare.secondsValue() ;
	}

bool	Interval :: operator>=	( Interval const & compare ) const
	{
	return secondsValue() >= compare.secondsValue() ;
	}
bool	Interval :: operator<=	( Interval const & compare ) const
	{
	return secondsValue() <= compare.secondsValue() ;
	}


void	Interval :: _compressDownward ()
	{
	while ( mPicoseconds > MegaLong )
		{
		mPicoseconds	-=	MegaLong ;
		mMicroseconds	+=	1 ;
		}
	
	while ( mMicroseconds > MegaLong )
		{
		mMicroseconds	-=	MegaLong ;
		mSeconds		+=	1 ;
		}
	}
void	Interval :: _compressUpward ()
	{
	while ( mPicoseconds < 0 )
		{
		mPicoseconds	+=	MegaLong ;
		mMicroseconds	-=	1 ;
		}
	
	while ( mMicroseconds < 0 )
		{
		mMicroseconds	+=	MegaLong ;
		mSeconds		-=	1 ;
		}
	}

















Location :: Location	()
:	x	( 0 )
,	y	( 0 )
	{
	
	}
Location :: Location	( double const & inX , double const & inY )
:	x	( inX )
,	y	( inY )
	{
	
	}
Location :: Location	( Location const & copy )
:	x	( copy.x )
,	y	( copy.y )
	{
	
	}
Location :: ~Location	()
	{
	
	}


double	Location :: distanceFrom	( Location const & other ) const
	{
	double	dX	=	other.x - x ;
	double	dY	=	other.y - y ;
	return ::sqrt ( (dX*dX) + (dY*dY) ) ;
	}

bool	Location :: operator==		( Location const & compare ) const
	{
	return compare.x==x && compare.y==y ;
	}

Location& Location :: operator=		( Location const & copy )
	{
	x = copy.x ;
	y = copy.y ;
	return *this ;
	}






Channel :: Channel	()
:	identifier	( Unidentified )
	{
	
	}
Channel :: Channel	( Channel const & copy )
:	identifier	( copy.identifier )
	{
	
	}
Channel :: Channel	( Identifier inIdentifier )
:	identifier	( inIdentifier )
	{
	
	}
Channel :: ~Channel	()
	{
	
	}


Channel&	Channel :: operator=		( Channel const & copy )
	{
	identifier = copy.identifier ;
	return *this ;
	}

bool		Channel :: operator==		( Channel const & compare ) const
	{
	return identifier == compare.identifier ;
	}



